package com.luxsoft.siipap.em.replica.importadores.dbf;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;

import com.luxsoft.siipap.em.replica.importadores.ImportacionCanceledException;
import com.luxsoft.siipap.model.Periodo;
import com.luxsoft.siipap.replica.reader.DBFMapConverter;


/**
 * Simplifica el acceso directo a archivos DBF fechados (ej ALMACEXX.DBF) ,
 * en modo de solo de lectura
 * 
 * @author Ruben Cancino
 *
 */
public class DBFReaderTemplate {
	
	private String tabla;
	private String dbfDirPath;
	
	
	protected Logger logger=Logger.getLogger(getClass());
	
	protected String DEFAULT_DBF_DIR_PATH="g:\\siipap\\archivos\\dato2010\\";
	//protected String DEFAULT_DBF_DIR_PATH="C:\\Luxsoft\\proyectos\\SIIPAP_DATA\\Data\\2008\\";
	
	public List query(final Periodo p,final DBFRowMapper mapper,final DBFRowFilter filtro){
		return query(p, mapper, filtro,false);
	}
	
	public List query(final Periodo p,final DBFRowMapper mapper,final DBFRowFilter filtro,boolean excluirEliminados){
		
		List<Periodo> meses=Periodo.periodosMensuales(p);
		List data=new ArrayList();
		for(Periodo mes:meses){
			int m=Periodo.obtenerMes(mes.getFechaFinal())+1;
			try {
				List l=find(m, mapper,filtro,excluirEliminados);
				data.addAll(l);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return data;
	}
	
	
	
	public void execute(final Periodo p,final DBFRowHandler handler){
		logger.info("Procesando :"+p);
		List<Periodo> meses=Periodo.periodosMensuales(p);
		for(Periodo mes:meses){
			int m=Periodo.obtenerMes(mes.getFechaFinal());
			try {
				execute(m+1,handler);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	public void execute(final Periodo p,final DBFRowHandler handler,boolean excludeDeleted){
		logger.info("Procesando :"+p);
		List<Periodo> meses=Periodo.periodosMensuales(p);
		for(Periodo mes:meses){
			int m=Periodo.obtenerMes(mes.getFechaFinal());
			try {
				execute(m+1,handler,null,excludeDeleted);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	public void execute(int mes,final DBFRowHandler handler) throws IOException{
		execute(mes, handler,null);
	}
	
	public void execute(int mes,final DBFRowHandler handler,final DBFRowFilter filter) throws IOException{
		execute(mes, handler, filter,false);
	}
	
	public void execute(Date dia,final DBFRowHandler handler,final DBFRowFilter filter,boolean excluirEliminados) throws IOException{
		execute(Periodo.obtenerMes(dia)+1, handler,filter,excluirEliminados);
	}
	
	public void execute(int mes,final DBFRowHandler handler,final DBFRowFilter filter,boolean excluirEliminados) throws IOException{
		String path = getDataFilePath(mes);
		FileInputStream inputStream = new FileInputStream(path);
        try{
    		DBFMapConverter reader=new DBFMapConverter(inputStream);
            Map<String, Object> rowObjects;
            while ((rowObjects = reader.nextRecord()) != null) {
            	try {
            		if(filter!=null){
            			boolean incluir=filter.incluir(rowObjects);
            			if(!incluir) continue;
            		}
            		boolean deleted=(Boolean)rowObjects.get("ELIMINADO");
            		if(deleted && excluirEliminados)
            			continue;
            		else{
            			handler.processRow(rowObjects);
            		}
            			
				}catch (ImportacionCanceledException ce) {
					logger.info("Importacion cancelada");
					break;
				} catch (Exception e) {
					logger.error("Error al tratar de importar registro:\n "+ExceptionUtils.getRootCauseMessage(e)+"\n"
							+rowObjects,e);
					
					continue;
				}
            }
            
    	}finally{
    		inputStream.close();
    	}
	}
	
	public List find(int mes,final DBFRowMapper mapper,final DBFRowFilter filter) throws IOException{
		return find(mes, mapper, filter, false);
	}
	
	public List find(int mes,final DBFRowMapper mapper,final DBFRowFilter filter,boolean excluirEliminados) throws IOException{
		
		String path = getDataFilePath(mes);
		logger.info("Parseando: "+path);
		List data=new ArrayList();
		FileInputStream inputStream = new FileInputStream(path);
        try{
    		DBFMapConverter reader=new DBFMapConverter(inputStream);
            Map<String, Object> rowObjects;
            while ((rowObjects = reader.nextRecord()) != null) {
            	
            	try {
            		if(filter!=null){
            			boolean incluir=filter.incluir(rowObjects);
            			if(!incluir) continue;
            		}
            			
            		boolean deleted=(Boolean)rowObjects.get("ELIMINADO");
            		if(deleted && excluirEliminados)
            			continue;
            		else{
            			
            			if(mapper!=null){
            				Object obj=mapper.map(rowObjects);
            				//logger.info("Objeto creado: "+obj);
            				data.add(obj);
            			}else
            				data.add(rowObjects);
            		}
            			
				}catch (ImportacionCanceledException ce) {
					logger.info("Importacion cancelada");
					break;
				} catch (Exception e) {
					e.printStackTrace();
					logger.error("Error al tratar de importar registro: "+rowObjects,e);
					continue;
				}
            }
            
    	}finally{
    		try {
    			inputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
    		
    	}
    	return data;
	}
	
	
	public int queryForInt(final Date dia,DBFRowFilter filter,final boolean excluirEliminados) throws IOException{
		final List data=new ArrayList();
		DBFRowHandler handler=new DBFRowHandler(){
			public void processRow(Map<String, Object> row) throws Exception {
				data.add(1);
			}
		};
		execute(dia,handler,filter,excluirEliminados);
		return data.size();
				
	}
	
	
	
	
	/**
	 * Regresa la ruta para el archivo DBF del mes indicado
	 * Solo util para los archivos fechados
	 * 
	 * @param mes
	 * @return
	 * @throws IOException
	 */
	protected String  getDataFilePath(int mes) throws IOException{
		String tabla=getTabla()+StringUtils.leftPad(String.valueOf(mes),2,'0')+".DBF";
		String path = getDbfDirPath()+tabla;
        return path;
	}
	
	public String getTabla() {
		return tabla;
	}

	public void setTabla(String tabla) {
		this.tabla = tabla;
	}

	public String getDbfDirPath() {
		if(dbfDirPath==null)
			dbfDirPath=DEFAULT_DBF_DIR_PATH;
		return dbfDirPath;
	}

	public void setDbfDirPath(String dbfDirPath) {
		this.dbfDirPath = dbfDirPath;
	}
	
	public static void main(String[] args) throws IOException {
		DBFReaderTemplate template=new DBFReaderTemplate();
		template.setTabla("MOVCRE");
		template.execute(3, new DBFRowHandler(){

			public void processRow(Map<String, Object> row) throws Exception {
				/*Date fo=(Date)row.get("ALMFECHA");
				if( ((String)row.get("ALMTIPO")).equals("FAC")){
					boolean togo= DateUtils.isSameDay(DateUtil.toDate("02/03/2009"), fo);	
					if(togo){
						String serie=(String)row.get("ALMSERIE");
						if(serie.equals("C")){
							System.out.println(row);
						}
						
					}
				}
				*/
				System.out.println(row);
				
			}
			
		});
	}

}
